package com.dollar.juc.dynamicThreadPool.alarm;

import com.dollar.juc.dynamicThreadPool.DynamicThreadPoolManager;
import com.dollar.juc.dynamicThreadPool.KittyThreadPoolExecutor;
import com.dollar.juc.dynamicThreadPool.common.AlarmManager;
import com.dollar.juc.dynamicThreadPool.common.AlarmMessage;
import com.dollar.juc.dynamicThreadPool.common.AlarmTypeEnum;
import com.dollar.juc.dynamicThreadPool.config.DynamicThreadPoolProperties;
import com.dollar.juc.dynamicThreadPool.config.ThreadPoolProperties;
import com.dollar.juc.dynamicThreadPool.util.JsonUtils;

import javax.annotation.PostConstruct;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 线程池告警
 */
public class DynamicThreadPoolAlarm {

    private DynamicThreadPoolManager dynamicThreadPoolManager;

    private DynamicThreadPoolProperties dynamicThreadPoolProperties;

    private ThreadPoolAlarmNotify threadPoolAlarmNotify;

    public DynamicThreadPoolAlarm(DynamicThreadPoolManager dynamicThreadPoolManager, ThreadPoolAlarmNotify threadPoolAlarmNotify, boolean useDefaultAlarm) {
        this.dynamicThreadPoolManager = dynamicThreadPoolManager;
        this.threadPoolAlarmNotify = threadPoolAlarmNotify;
        this.useDefaultAlarm = useDefaultAlarm;
    }

    /**
     * 应用名称，告警用到
     */
    private String applicationName;

    /**
     * 是否使用默认告警
     */
    private boolean useDefaultAlarm;

    public void initAlarm() {
        new Thread(() -> {
            while (true) {
                Map<String, KittyThreadPoolExecutor> threadPoolMap = dynamicThreadPoolManager.getThreadPoolMap();
                System.out.println("threadPoolMap: " + threadPoolMap);
                for (Map.Entry<String, KittyThreadPoolExecutor> entry : threadPoolMap.entrySet()) {
                    KittyThreadPoolExecutor threadPoolExecutor = entry.getValue();
                    String threadPoolName = entry.getKey();
                    System.out.println(dynamicThreadPoolManager.getThreadPoolInfo(threadPoolName));
                    int queueCapacityThreshold = dynamicThreadPoolManager.getQueueCapacityThreshold();
                    int taskCount = threadPoolExecutor.getQueue().size();
                    if (taskCount > queueCapacityThreshold) {
                        sendQueueCapacityThresholdAlarmMessage(null, taskCount);
                    }

                    AtomicLong rejectCount = dynamicThreadPoolManager.getRejectCount(threadPoolName);
                    if (rejectCount != null && rejectCount.get() > 0) {
                        sendRejectAlarmMessage(rejectCount.get(), null);
                        // 清空拒绝数据
                        //dynamicThreadPoolManager.clearRejectCount(threadPoolName);
                    }
                }
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    public void init() {
        new Thread(() -> {
            while (true) {
                dynamicThreadPoolProperties.getExecutors().stream().forEach(prop -> {
                    String threadPoolName = prop.getThreadPoolName();
                    KittyThreadPoolExecutor threadPoolExecutor = dynamicThreadPoolManager.getThreadPoolExecutor(threadPoolName);

                    dynamicThreadPoolManager.registerStatusExtension(prop, threadPoolExecutor);

                    int queueCapacityThreshold = prop.getQueueCapacityThreshold();
                    int taskCount = threadPoolExecutor.getQueue().size();
                    if (taskCount > queueCapacityThreshold) {
                        sendQueueCapacityThresholdAlarmMessage(prop, taskCount);
                    }

                    AtomicLong rejectCount = dynamicThreadPoolManager.getRejectCount(threadPoolName);
                    if (rejectCount != null && rejectCount.get() > 0) {
                        sendRejectAlarmMessage(rejectCount.get(), prop);
                        // 清空拒绝数据
                        dynamicThreadPoolManager.clearRejectCount(threadPoolName);
                    }

                });
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    private void sendRejectAlarmMessage(long rejectCount, ThreadPoolProperties prop) {
        AlarmMessage alarmMessage = AlarmMessage.builder()
                .alarmName("rejectCount")
                .alarmType(getAlarmType())
//                .apiUrl(dynamicThreadPoolProperties.getAlarmApiUrl())
//                .message(getRejectCountMessage(rejectCount, prop))
//                .accessToken(dynamicThreadPoolProperties.getAccessToken())
//                .secret(dynamicThreadPoolProperties.getSecret())
//                .alarmTimeInterval(dynamicThreadPoolProperties.getAlarmTimeInterval())
                .build();

        if (useDefaultAlarm) {
            AlarmManager.sendAlarmMessage(alarmMessage);
        }

        alarmNotify(alarmMessage);
    }

    private void sendQueueCapacityThresholdAlarmMessage(ThreadPoolProperties prop, int taskCount) {
        AlarmMessage alarmMessage = AlarmMessage.builder()
                .alarmName("queueCapacityThreshold")
                .alarmType(getAlarmType())
//                .apiUrl(dynamicThreadPoolProperties.getAlarmApiUrl())
//                .message(getQueueCapacityThresholdMessage(prop, taskCount))
//                .accessToken(dynamicThreadPoolProperties.getAccessToken())
//                .secret(dynamicThreadPoolProperties.getSecret())
//                .alarmTimeInterval(dynamicThreadPoolProperties.getAlarmTimeInterval())
                .build();

        if (useDefaultAlarm) {
            AlarmManager.sendAlarmMessage(alarmMessage);
        }

        alarmNotify(alarmMessage);
    }

    private void alarmNotify(AlarmMessage alarmMessage) {
        if (threadPoolAlarmNotify != null) {
            threadPoolAlarmNotify.alarmNotify(alarmMessage);
        }
    }

    private String getQueueCapacityThresholdMessage(ThreadPoolProperties prop, int taskCount) {
        return getAlarmMessage("线程池出现任务堆积情况,队列容量:" + prop.getQueueCapacity() + ",等待执行任务数量:" + taskCount, prop);
    }

    private String getRejectCountMessage(long rejectCount, ThreadPoolProperties prop) {
        return getAlarmMessage("线程池中出现RejectedExecutionException异常" + rejectCount + "次", prop);
    }

    private String getAlarmMessage(String reason, ThreadPoolProperties prop) {
        StringBuilder content = new StringBuilder();
        content.append("告警应用:").append(applicationName).append("\n");
        content.append("线程池名称:").append(prop.getThreadPoolName()).append("\n");
        content.append("告警原因:").append(reason).append("\n");
        content.append("参数信息:").append(formatThreadPoolParam(prop));
        content.append("业务负责人:").append(dynamicThreadPoolProperties.getOwner()).append("\n");
        content.append("告警间隔:").append(dynamicThreadPoolProperties.getAlarmTimeInterval()).append("分钟\n");
        return content.toString();
    }

    private String formatThreadPoolParam(ThreadPoolProperties prop) {
        StringBuilder content = new StringBuilder("\n");
        Map map = JsonUtils.toBean(Map.class, JsonUtils.toJson(prop));
        map.forEach((k, v) -> {
            content.append(k).append(":").append(v).append("\n");
        });
        return content.toString();
    }

    private AlarmTypeEnum getAlarmType() {
//        return StringUtils.hasText(dynamicThreadPoolProperties.getAlarmApiUrl()) ? AlarmTypeEnum.EXTERNAL_SYSTEM : AlarmTypeEnum.DING_TALK;
        return AlarmTypeEnum.EXTERNAL_SYSTEM;
    }

}
